"use client";

// 导入必要的React钩子和类型
import Oeact, { useState, useEffect, useRef } from "react";
import {
  JointState,          // 关节状态类型
  UpdateJointDegrees,   // 更新单个关节角度的函数类型
  UpdateJointsDegrees,  // 批量更新关节角度的函数类型
} from "../../../hooks/useRobotControl";
import { radiansToDegrees } from "../../../lib/utils";  // 弧度转角度的工具函数
import { RobotConfig } from "@/config/robotConfig";     // 机器人配置类型

/**
 * RevoluteJointsTable组件的属性类型定义
 */
type RevoluteJointsTableProps = {
  joints: JointState[];                                  // 关节状态数组
  updateJointDegrees: UpdateJointDegrees;                // 更新单个关节角度的函数
  updateJointsDegrees: UpdateJointsDegrees;              // 批量更新关节角度的函数
  keyboardControlMap: RobotConfig["keyboardControlMap"]; // 键盘控制映射
  compoundMovements?: RobotConfig["compoundMovements"]; // 复合运动配置（可选）
};

// 定义按键更新的常量
const KEY_UPDATE_INTERVAL_MS = 3;      // 按键更新间隔（毫秒）
const KEY_UPDATE_STEP_DEGREES = 0.15;  // 每次更新的角度步长

/**
 * 格式化虚拟角度显示
 * @param degrees 角度值
 * @returns 格式化后的角度字符串，包含正负号和单位
 */
const formatVirtualDegrees = (degrees?: number) =>
  degrees !== undefined
    ? `${degrees > 0 ? "+" : ""}${degrees.toFixed(1)}°`
    : "/";

/**
 * 格式化实际角度显示
 * @param degrees 角度值或特殊状态（N/A、error）
 * @returns 格式化后的角度显示组件
 */
const formatRealDegrees = (degrees?: number | "N/A" | "error") => {
  if (degrees === "error") {
    return <span className="text-red-500">Error</span>;
  }
  return degrees === "N/A" ? "/" : `${degrees?.toFixed(1)}°`;
};

/**
 * 复合运动按键约定：
 * - keys[0]：正向运动的按键
 * - keys[1]：反向运动的按键
 * 例如 keys: ["8", "i"]，"8"控制正向，"i"控制反向
 */

/**
 * 旋转关节控制表格组件
 * 用于显示和控制机器人的旋转关节，支持键盘控制和鼠标/触摸控制
 */
export function RevoluteJointsTable({
  joints,                // 关节状态数组
  updateJointDegrees,    // 更新单个关节角度的函数
  updateJointsDegrees,   // 批量更新关节角度的函数
  keyboardControlMap,    // 键盘控制映射
  compoundMovements,     // 复合运动配置
}: RevoluteJointsTableProps) {
  // 记录当前按下的按键集合
  const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());

  // 使用 refs 存储最新的 props 值，以便在回调函数中访问
  const jointsRef = useRef(joints);
  const updateJointsDegreesRef = useRef(updateJointsDegrees);
  const keyboardControlMapRef = useRef(keyboardControlMap);

  // 当 props 更新时，同步更新对应的 ref
  useEffect(() => {
    jointsRef.current = joints;
  }, [joints]);

  useEffect(() => {
    updateJointsDegreesRef.current = updateJointsDegrees;
  }, [updateJointsDegrees]);

  useEffect(() => {
    keyboardControlMapRef.current = keyboardControlMap;
  }, [keyboardControlMap]);

  /**
   * 键盘事件监听器设置
   * 处理按键按下和释放事件，更新 pressedKeys 状态
   */
  useEffect(() => {
    // 处理按键按下事件
    const handleKeyDown = (event: KeyboardEvent) => {
      // 检查按下的键是否用于控制
      const isControlKey = Object.values(keyboardControlMapRef.current || {})
        .flat()
        .includes(event.key);
      
      // 可选：阻止方向键等按键的默认行为（如页面滚动）
      if (isControlKey) {
        // event.preventDefault();
      }
      
      // 将按下的键添加到 pressedKeys 集合中
      setPressedKeys((prevKeys) => new Set(prevKeys).add(event.key));
    };

    // 处理按键释放事件
    const handleKeyUp = (event: KeyboardEvent) => {
      setPressedKeys((prevKeys) => {
        const newKeys = new Set(prevKeys);
        newKeys.delete(event.key);
        return newKeys;
      });
    };

    // 添加事件监听器
    window.addEventListener("keydown", handleKeyDown);
    window.addEventListener("keyup", handleKeyUp);

    // 清理函数：移除事件监听器
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, []); // 空依赖数组：仅在组件挂载时设置一次监听器

  /**
   * 按键持续更新效果
   * 当有按键被按下时，定期更新关节角度
   */
  useEffect(() => {
    let intervalId: NodeJS.Timeout | null = null;

    // 根据当前按下的按键更新关节角度
    const updateJointsBasedOnKeys = () => {
      // 获取当前状态的快照
      const currentJoints = jointsRef.current;
      const currentControlMap = keyboardControlMapRef.current || {};
      const currentPressedKeys = pressedKeys;
      const currentCompoundMovements = compoundMovements || [];

      /**
       * 处理普通单关节控制
       * 遍历所有关节，根据按键状态更新关节角度
       */
      let updates = currentJoints
        .map((joint) => {
          // 获取当前关节的控制按键
          const decreaseKey = currentControlMap[joint.servoId!]?.[1];  // 减小角度的按键
          const increaseKey = currentControlMap[joint.servoId!]?.[0];  // 增加角度的按键
          let currentDegrees = joint.virtualDegrees || 0;             // 当前角度
          let newValue = currentDegrees;                              // 新角度值

          // 根据按键状态更新角度值
          if (decreaseKey && currentPressedKeys.has(decreaseKey)) {
            newValue -= KEY_UPDATE_STEP_DEGREES;  // 减小角度
          }
          if (increaseKey && currentPressedKeys.has(increaseKey)) {
            newValue += KEY_UPDATE_STEP_DEGREES;  // 增加角度
          }

          // 计算关节角度限制
          const lowerLimit = Math.round(
            radiansToDegrees(joint.limit?.lower ?? -Infinity)  // 下限
          );
          const upperLimit = Math.round(
            radiansToDegrees(joint.limit?.upper ?? Infinity)   // 上限
          );
          // 确保新角度在限制范围内
          newValue = Math.max(lowerLimit, Math.min(upperLimit, newValue));

          // 只在角度发生变化时返回更新信息
          if (newValue !== currentDegrees) {
            return { servoId: joint.servoId!, value: newValue };
          }
          return null;
        })
        .filter((update) => update !== null) as {
        servoId: number;  // 伺服电机ID
        value: number;    // 新的角度值
      }[];

      /**
       * 处理复合运动
       * 复合运动的优先级高于普通单关节控制
       */
      currentCompoundMovements.forEach((cm) => {
        // 检查是否有复合运动的控制键被按下
        const pressedIdx = cm.keys.findIndex((k) => currentPressedKeys.has(k));
        if (pressedIdx === -1) return;  // 没有相关按键被按下

        // 获取主关节信息
        const primaryJoint = currentJoints.find(
          (j) => j.servoId === cm.primaryJoint
        );
        if (!primaryJoint) return;  // 主关节不存在
        const primary = primaryJoint.virtualDegrees || 0;

        // 获取从属关节信息
        const dependentJointId = cm.dependents[0]?.joint;
        const dependentJoint = currentJoints.find(
          (j) => j.servoId === dependentJointId
        );
        const dependent = dependentJoint?.virtualDegrees || 0;

        /**
         * 计算运动方向
         * sign 决定方向：+1 表示正向，-1 表示反向
         */
        let sign = 1;
        if (cm.primaryFormula) {
          try {
            // 使用自定义公式计算运动方向
            sign =
              Math.sign(
                Function(
                  "primary",
                  "dependent",
                  "delta",
                  `return ${cm.primaryFormula}`
                )(primary, dependent, KEY_UPDATE_STEP_DEGREES)
              ) || 1;
          } catch (e) {
            sign = 1;  // 公式执行出错时默认为正向
          }
        } else {
          // 没有自定义公式时，根据按键确定方向
          sign = pressedIdx === 0 ? 1 : -1;
        }

        // 计算主关节的角度变化
        const deltaPrimary =
          KEY_UPDATE_STEP_DEGREES * sign * (pressedIdx === 0 ? 1 : -1);

        // 计算主关节的新角度值并应用限制
        let newPrimaryValue = primary + deltaPrimary;
        const lowerLimit = Math.round(
          radiansToDegrees(primaryJoint.limit?.lower ?? -Infinity)
        );
        const upperLimit = Math.round(
          radiansToDegrees(primaryJoint.limit?.upper ?? Infinity)
        );
        newPrimaryValue = Math.max(
          lowerLimit,
          Math.min(upperLimit, newPrimaryValue)
        );

        // 使用Map存储更新值，确保不会重复更新同一关节
        const updatesMap = new Map<number, number>();
        updates.forEach((u) => updatesMap.set(u.servoId, u.value));
        updatesMap.set(primaryJoint.servoId!, newPrimaryValue);

        /**
         * 处理从属关节的更新
         * 根据主关节的变化计算从属关节的新角度
         */
        cm.dependents.forEach((dep) => {
          // 获取从属关节信息
          const dependentJoint = currentJoints.find(
            (j) => j.servoId === dep.joint
          );
          if (!dependentJoint) return;  // 从属关节不存在
          const dependent = dependentJoint.virtualDegrees || 0;

          // 计算从属关节的角度变化
          let deltaDependent = 0;
          try {
            // 使用自定义公式计算从属关节的角度变化
            deltaDependent = Function(
              "primary",
              "dependent",
              "deltaPrimary",
              `return ${dep.formula}`
            )(primary, dependent, deltaPrimary);
          } catch (e) {
            deltaDependent = 0;  // 公式执行出错时不进行角度变化
          }

          // 确保计算结果是有效数字
          if (!Number.isFinite(deltaDependent)) {
            deltaDependent = 0;
          }

          // 计算从属关节的新角度值
          let newDependentValue = dependent + deltaDependent;

          // 应用从属关节的角度限制
          const depLowerLimit = Math.round(
            radiansToDegrees(dependentJoint.limit?.lower ?? -Infinity)
          );
          const depUpperLimit = Math.round(
            radiansToDegrees(dependentJoint.limit?.upper ?? Infinity)
          );
          newDependentValue = Math.max(
            depLowerLimit,
            Math.min(depUpperLimit, newDependentValue)
          );

          // 更新从属关节的角度值
          updatesMap.set(dependentJoint.servoId!, newDependentValue);
        });

        // 将Map中的更新转换为数组格式
        updates = Array.from(updatesMap.entries()).map(([servoId, value]) => ({
          servoId,
          value,
        }));
      });

      // 如果有需要更新的关节，执行批量更新
      if (updates.length > 0) {
        updateJointsDegreesRef.current(updates);
      }
    };

    // 当有按键被按下时，启动定时更新
    if (pressedKeys.size > 0) {
      intervalId = setInterval(updateJointsBasedOnKeys, KEY_UPDATE_INTERVAL_MS);
    }

    // 清理函数：停止定时更新
    return () => {
      if (intervalId) {
        clearInterval(intervalId);
      }
    };
  }, [pressedKeys]); // 仅在 pressedKeys 变化时重新运行此效果

  /**
   * 鼠标事件处理函数
   * 用于处理控制按钮的鼠标按下和释放事件
   */
  const handleMouseDown = (key: string | undefined) => {
    if (key) {
      // 将按下的按键添加到 pressedKeys 集合中
      setPressedKeys((prevKeys) => new Set(prevKeys).add(key));
    }
  };

  const handleMouseUp = (key: string | undefined) => {
    if (key) {
      // 从 pressedKeys 集合中移除释放的按键
      setPressedKeys((prevKeys) => {
        const newKeys = new Set(prevKeys);
        newKeys.delete(key);
        return newKeys;
      });
    }
  };

  /**
   * 组件渲染
   * 包含关节控制表格和复合运动控制界面
   */
  return (
    <div className="mt-4">
      {/* 关节控制表格 */}
      <table className="table-auto w-full text-left text-sm">
        <thead>
          <tr>
            <th className="border-b border-gray-600 pb-1 pr-2">关节名称</th>
            <th className="border-b border-gray-600 pb-1 text-center pl-2">
              虚拟角度
            </th>
            <th className="border-b border-gray-600 pb-1 text-center pl-2">
              实际角度
            </th>
            <th className="border-b border-gray-600 pb-1 text-center px-2">
              控制
            </th>
          </tr>
        </thead>
        <tbody>
          {/* 遍历所有关节，渲染控制界面 */}
          {joints.map((detail) => {
            // 获取当前关节的控制按键和状态
            const decreaseKey = keyboardControlMap?.[detail.servoId!]?.[1];  // 减小角度的按键
            const increaseKey = keyboardControlMap?.[detail.servoId!]?.[0];  // 增加角度的按键
            const isDecreaseActive = decreaseKey && pressedKeys.has(decreaseKey);  // 减小按键是否激活
            const isIncreaseActive = increaseKey && pressedKeys.has(increaseKey);  // 增加按键是否激活

            return (
              <tr key={detail.servoId}>
                {/* 关节名称 */}
                <td className="">
                  {detail.name}
                </td>

                {/* 虚拟角度显示 */}
                <td className="pr-2 text-center w-16">
                  {formatVirtualDegrees(detail.virtualDegrees)}
                </td>
                {/* 实际角度显示 */}
                <td className="pl-2 text-center w-16">
                  {formatRealDegrees(detail.realDegrees)}
                </td>
                {/* 控制按钮和滑块 */}
                <td className="py-1 px-4 flex items-center">
                  {/* 减小角度按钮 */}
                  <button
                    onMouseDown={() => handleMouseDown(decreaseKey)}
                    onMouseUp={() => handleMouseUp(decreaseKey)}
                    onMouseLeave={() => handleMouseUp(decreaseKey)}  // 鼠标离开时释放按键
                    onTouchStart={() => handleMouseDown(decreaseKey)} // 触摸支持
                    onTouchEnd={() => handleMouseUp(decreaseKey)}     // 触摸支持
                    className={`${
                      isDecreaseActive
                        ? "bg-blue-600"  // 按下状态
                        : "bg-gray-700 hover:bg-gray-600"  // 普通状态
                    } text-white text-xs font-bold w-5 h-5 text-right pr-1 uppercase select-none`}
                    style={{
                      clipPath: "polygon(0 50%, 30% 0, 100% 0, 100% 100%, 30% 100%)",  // 箭头形状
                    }}
                  >
                    {decreaseKey || "-"}
                  </button>

                  {/* 角度滑块控制 */}
                  <input
                    type="range"
                    min={Math.round(radiansToDegrees(detail.limit?.lower ?? -Math.PI))}  // 最小角度
                    max={Math.round(radiansToDegrees(detail.limit?.upper ?? Math.PI))}   // 最大角度
                    step="0.1"  // 步进值
                    value={detail.virtualDegrees || 0}
                    onChange={(e) => {
                      // 滑块值改变时更新关节角度
                      const valueInDegrees = parseFloat(e.target.value);
                      updateJointDegrees(detail.servoId!, valueInDegrees);
                    }}
                    className="h-2 bg-gray-700 appearance-none cursor-pointer w-14 custom-range-thumb"
                  />

                  {/* 增加角度按钮 */}
                  <button
                    onMouseDown={() => handleMouseDown(increaseKey)}
                    onMouseUp={() => handleMouseUp(increaseKey)}
                    onMouseLeave={() => handleMouseUp(increaseKey)}  // 鼠标离开时释放按键
                    onTouchStart={() => handleMouseDown(increaseKey)} // 触摸支持
                    onTouchEnd={() => handleMouseUp(increaseKey)}     // 触摸支持
                    className={`${
                      isIncreaseActive
                        ? "bg-blue-600"  // 按下状态
                        : "bg-gray-700 hover:bg-gray-600"  // 普通状态
                    } text-white text-xs font-semibold w-5 h-5 text-left pl-1 uppercase select-none`}
                    style={{
                      clipPath: "polygon(100% 50%, 70% 0, 0 0, 0 100%, 70% 100%)",  // 箭头形状
                    }}
                  >
                    {increaseKey || "+"}
                  </button>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>

      {/* 复合运动控制界面 */}
      {compoundMovements && compoundMovements.length > 0 && (
        <div className="mt-4">
          <div className="font-bold mb-2">复合运动</div>
          <table className="table-auto w-full text-left text-sm">
            <tbody>
              {compoundMovements.map((cm, idx) => {
                // 获取复合运动的控制按键和状态
                const decreaseKey = cm.keys[1];  // 反向运动按键
                const increaseKey = cm.keys[0];  // 正向运动按键
                const isDecreaseActive = decreaseKey && pressedKeys.has(decreaseKey);  // 反向按键是否激活
                const isIncreaseActive = increaseKey && pressedKeys.has(increaseKey);  // 正向按键是否激活

                return (
                  <tr key={idx}>
                    {/* 复合运动名称 */}
                    <td className="font-semibold pr-2 align-top">{cm.name}</td>
                    <td>
                      {/* 复合运动控制按钮 */}
                      {cm.keys && cm.keys.length > 0 && (
                        <span className="space-x-1 flex flex-row">
                          {/* 反向运动按钮 */}
                          <button
                            onMouseDown={() => handleMouseDown(decreaseKey)}
                            onMouseUp={() => handleMouseUp(decreaseKey)}
                            onMouseLeave={() => handleMouseUp(decreaseKey)}
                            onTouchStart={() => handleMouseDown(decreaseKey)}
                            onTouchEnd={() => handleMouseUp(decreaseKey)}
                            className={`${
                              isDecreaseActive
                                ? "bg-blue-600"  // 按下状态
                                : "bg-gray-700 hover:bg-gray-600"  // 普通状态
                            } text-white text-xs font-bold w-5 h-5 text-right pr-1 uppercase select-none`}
                            style={{
                              clipPath: "polygon(0 50%, 30% 0, 100% 0, 100% 100%, 30% 100%)",  // 箭头形状
                              minWidth: "1.8em",
                              minHeight: "1.8em",
                              fontWeight: 600,
                              boxShadow: "0 1px 2px 0 rgba(0,0,0,0.04)",
                            }}
                            tabIndex={-1}
                          >
                            {decreaseKey || "-"}
                          </button>

                          {/* 正向运动按钮 */}
                          <button
                            onMouseDown={() => handleMouseDown(increaseKey)}
                            onMouseUp={() => handleMouseUp(increaseKey)}
                            onMouseLeave={() => handleMouseUp(increaseKey)}
                            onTouchStart={() => handleMouseDown(increaseKey)}
                            onTouchEnd={() => handleMouseUp(increaseKey)}
                            className={`${
                              isIncreaseActive
                                ? "bg-blue-600"  // 按下状态
                                : "bg-gray-700 hover:bg-gray-600"  // 普通状态
                            } text-white text-xs font-semibold w-5 h-5 text-left pl-1 uppercase select-none`}
                            style={{
                              clipPath: "polygon(100% 50%, 70% 0, 0 0, 0 100%, 70% 100%)",  // 箭头形状
                              minWidth: "1.8em",
                              minHeight: "1.8em",
                              fontWeight: 600,
                              boxShadow: "0 1px 2px 0 rgba(0,0,0,0.04)",
                            }}
                            tabIndex={-1}
                          >
                            {increaseKey || "+"}
                          </button>
                        </span>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {/* 自定义滑块样式 */}
      <style jsx global>{`
        /* Webkit（Chrome、Safari等）的滑块样式 */
        .custom-range-thumb::-webkit-slider-thumb {
          -webkit-appearance: none;
          appearance: none;
          width: 8px;
          height: 8px;
          border-radius: 50%;
          background: #fff;
          cursor: pointer;
        }
        /* Firefox的滑块样式 */
        .custom-range-thumb::-moz-range-thumb {
          width: 8px;
          height: 8px;
          border-radius: 50%;
          background: #fff;
          cursor: pointer;
        }
        /* Edge的滑块样式 */
        .custom-range-thumb::-ms-thumb {
          width: 8px;
          height: 8px;
          border-radius: 50%;
          background: #fff;
          cursor: pointer;
        }
        /* Firefox的轨道样式 */
        .custom-range-thumb {
          overflow: hidden;
        }
        /* Chrome的轨道样式 */
        input[type="range"].custom-range-thumb {
          outline: none;
        }
      `}</style>
    </div>
  );
}
